﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using PSE.Deployment.SetupBase.Configuration;
using PSE.Deployment.SetupBase.Parameter;
using PSE.Deployment.Engine.CustomExceptions;
using PSE.Deployment.Engine.Interfaces;
using System.Diagnostics;

namespace PSE.Deployment.SetupBase.Steps
{
    public class Copy : SetupStep<Configuration.Actions.Copy>
    {
        public Copy(IStepGroup parent, Group group, Configuration.Actions.Copy action, Parameter.Enums.SetupMode setupMode)
            : base(parent, group, action, setupMode)
        {
            this.ResetProgress();
        }

        public override void Execute()
        {
            this.ResetProgress();

            if (this.SetupMode == Parameter.Enums.SetupMode.Install)
            {
                CopyFolders();
            }
            else if (this.SetupMode == Parameter.Enums.SetupMode.Uninstall)
            {
                UninstallArtefacts();
            }
        }

        public override void Undo()
        {
            if (this.SetupMode == Parameter.Enums.SetupMode.Install)
            {
                UninstallArtefacts();
            }
        }

        private void ResetProgress()
        {
            int count = 0;

            foreach (FolderInfo folderInfo in Action.Folders)
            {
                string path;

                if (Directory.Exists(SetupMainFactory.GetInstance().Parameter.InstalationSource))
                    path = Path.Combine(SetupMainFactory.GetInstance().Parameter.InstalationSource, folderInfo.Source);
                else
                    path = Path.Combine(SetupMainFactory.GetInstance().Parameter.InstallationPath, folderInfo.Destination);

                if (folderInfo.Files.Count == 0)
                {
                    count += PSE.Deployment.Util.File.CountFiles(path, "*.*");
                }
                else
                {
                    count += folderInfo.Files.Count;
                }
            }

            this.ResetProgress(count);
        }

        private void CopyFolders()
        {
            foreach (FolderInfo folderInfo in Action.Folders)
            {
                string sourceFolder = Path.Combine(SetupMainFactory.GetInstance().Parameter.InstalationSource, folderInfo.Source);
                string destinationFolder = Path.Combine(SetupMainFactory.GetInstance().Parameter.InstallationPath, folderInfo.Destination);

                if (folderInfo.Files.Count == 0)
                {
                    if (Directory.Exists(sourceFolder))
                        CopyFiles(sourceFolder, destinationFolder, Directory.GetFiles(sourceFolder, "*.*", SearchOption.AllDirectories));
                }
                else
                {
                    CopyFiles(sourceFolder, destinationFolder, PSE.Deployment.Util.File.GetFiles(sourceFolder, folderInfo.Files));
                }
            }
        }

        private void CopyFiles(string sourceFolder, string destinationFolder, IEnumerable<string> files)
        {
            foreach (string file in files)
            {
                if (this.IsStopped())
                    break;

                string source;
                string destination;

                if (Path.IsPathRooted(file))
                {
                    source = file;
                    destination = file.Replace(sourceFolder, destinationFolder);
                }
                else
                {
                    source = Path.Combine(sourceFolder, file);
                    destination = Path.Combine(destinationFolder, file);
                }

                if (!Directory.Exists(Path.GetDirectoryName(destination)))
                    Directory.CreateDirectory(Path.GetDirectoryName(destination));

                this.IncrementProgress(destination);

                try
                {
                    bool isValid = true;

                    if (SetupMainFactory.GetInstance().Parameter.SetupMode != PSE.Deployment.SetupBase.Parameter.Enums.SetupMode.HotFix &&
                        SetupMainFactory.GetInstance().Parameter.SetupMode != PSE.Deployment.SetupBase.Parameter.Enums.SetupMode.ServicePack)
                    {
                        isValid = !SetupMainFactory.GetInstance().Parameter.InstalledArtefacts.Contains(destination);
                    }

                    if (isValid)
                    {
                        if (File.Exists(destination))
                        {
                            File.SetAttributes(destination, FileAttributes.Normal);
                        }

                        File.Copy(source, destination, true);

                        File.SetAttributes(destination, FileAttributes.Normal);
                    }

                    this.AddUsedBy(destination);
                }
                catch
                {
                    this.DecrementProgress(destination);
                    throw;
                }
            }
        }

        protected override void UninstallArtefact(string artefactName)
        {
            if (Process.GetProcessesByName(Path.GetFileNameWithoutExtension(artefactName)).Length > 0)
            {
                PSE.Deployment.Util.Windows.KillProcess(Path.GetFileNameWithoutExtension(artefactName));
            }

            if (File.Exists(artefactName))
                File.Delete(artefactName);

            if (Directory.Exists(Path.GetDirectoryName(artefactName)))
                PSE.Deployment.Util.File.DeleteEmptyDirectories(SetupMainFactory.GetInstance().Parameter.InstallationPath, Path.GetDirectoryName(artefactName));
        }
    }
}
